

package com.guoyan.blockchain.common.client;

import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
import org.hyperledger.fabric.sdk.TransactionRequest.Type;
import org.hyperledger.fabric.sdk.exception.ChaincodeEndorsementPolicyParseException;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ChannelClient {

    private String name;
    private Channel channel;
    private FabricClient fabClient;

    public String getName() {
        return name;
    }

    public Channel getChannel() {
        return channel;
    }

    public FabricClient getFabClient() {
        return fabClient;
    }

    public ChannelClient(String name, Channel channel, FabricClient fabClient) {
        this.name = name;
        this.channel = channel;
        this.fabClient = fabClient;
    }

    public Collection<ProposalResponse> queryByChainCode(String chaincodeName, String functionName, String[] args) throws InvalidArgumentException, ProposalException {
        QueryByChaincodeRequest request = fabClient.getInstance().newQueryProposalRequest();
        ChaincodeID ccid = ChaincodeID.newBuilder().setName(chaincodeName).build();
        request.setChaincodeID(ccid);
        request.setFcn(functionName);
        if (args != null) {
            request.setArgs(args);
        }
        return channel.queryByChaincode(request);
    }

    public Collection<ProposalResponse> sendTransactionProposal(TransactionProposalRequest request) throws ProposalException, InvalidArgumentException {
        //		CompletableFuture<TransactionEvent> cf = channel.sendTransaction(response);
//		System.out.println(cf.toString());
        return channel.sendTransactionProposal(request, channel.getPeers());
    }

    public CompletableFuture<TransactionEvent> sendTransaction(Collection<ProposalResponse> response) throws ExecutionException, InterruptedException {
        return channel.sendTransaction(response);
    }

    public Collection<ProposalResponse> instantiateChainCode(String chaincodeName, String version, Collection<Peer> peers, String language, String functionName, String[] functionArgs, String policyPath)
            throws InvalidArgumentException, ProposalException, ChaincodeEndorsementPolicyParseException, IOException {
        InstantiateProposalRequest instantiateProposalRequest = fabClient.getInstance().newInstantiationProposalRequest();
        instantiateProposalRequest.setProposalWaitTime(1800000);
        ChaincodeID.Builder chainCodeIDBuilder = ChaincodeID.newBuilder().setName(chaincodeName).setVersion(version);
        ChaincodeID ccid = chainCodeIDBuilder.build();
        instantiateProposalRequest.setChaincodeID(ccid);
        if (language.equals(Type.GO_LANG.toString())) {
            instantiateProposalRequest.setChaincodeLanguage(Type.GO_LANG);
        } else {
            instantiateProposalRequest.setChaincodeLanguage(Type.JAVA);
        }
        instantiateProposalRequest.setFcn(functionName);
        instantiateProposalRequest.setArgs(functionArgs);
        if (policyPath != null) {
            ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy();
            chaincodeEndorsementPolicy.fromYamlFile(new File(policyPath));
            instantiateProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);
        }
        Collection<ProposalResponse> responses = channel.sendInstantiationProposal(instantiateProposalRequest, peers);
        channel.sendTransaction(responses);
        return responses;
    }

    public TransactionInfo queryByTransactionId(String txnId) throws ProposalException, InvalidArgumentException {
        Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO,
                "Querying by trasaction id " + txnId + " on channel " + channel.getName());
        Collection<Peer> peers = channel.getPeers();
        for (Peer peer : peers) {
            TransactionInfo info = channel.queryTransactionByID(peer, txnId);
            return info;
        }
        return null;
    }

}
